不用 promise, 那些可实现 promise generator
js
function* fun(x) {
let y = yield x + 1;
return y;
}
js
function getCallSettings() {
// utils.ajax方法支持返回promise对象,把得到的promise return出去
return utils.ajax({
url: "/dialer/dialerSetting",
method: "GET",
});
}
function* dealData() {
try {
let settingInfo = yield getCallSettings();
// do something……
} catch (err) {
console.log(err); // 接收错误
}
}
let it = dealData();
let promise = it.next().value; // 注意,这里拿到yield出来的promise
promise.then(
(info) => {
it.next(info); // 拿到info传给yield表达式
},
(err) => {
it.throw(err); // 抛出错误
}
);
js
function getCallSettings() {
return fetch('/')
}
function* dealData() {
try {
let settingInfo = yield getCallSettings();
console.log(settingInfo, 'mty');
// do something……
return settingInfo
} catch (err) {
console.log(err); // 接收错误
}
return 'abc';
}
let it = dealData();
let promise = it.next().value; // 注意,这里拿到yield出来的promise
promise.then(
(info) => {
it.next(info); // 拿到info传给yield表达式
},
(err) => {
it.throw(err); // 抛出错误
}
);
Generator 函数和普通函数有什么区别?
- generator 迭代器函数,可以暂停可以恢复,generator 是协程 在 ES6 实现,最大特点交出函数执行权,控制迭代器的函数,可以暂停可以恢复
- 不可以用箭头函数声明 -不能当构造函数使用
形式区别
- function 函数声明有个*
- 函数内部有 yield,定义不同状态,yield 只能在 generator 里
- 直接调用 generator 并不会立刻执行,而是返回一个迭代器对象 [iterator Object]
- 依次调用对象 next() 方法来执行,获取内部状态
生成器函数不能当构造器使用
function* f() {} var obj = new f; // throws "TypeError: f is not a constructor"
交出执行权
如果用的是 yield*(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。
js
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i); // 移交执行权
yield i + 10;
}
var gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
传递参数
如果传入了参数,那么这个参数会传给上一条执行的 yield 语句左边的变量
js
function* createIterator() {
let first = yield 1;
let second = yield first + 2; // 4 + 2
// first =4 是next(4)将参数赋给上一条的
yield second + 3; // 5 + 3
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.next(5)); // "{ value: 8, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
使用迭代器遍历二维数组并转换成一维数组:
js
function* iterArr(arr) {
//迭代器返回一个迭代器对象
if (Array.isArray(arr)) {
// 内节点
for (let i = 0; i < arr.length; i++) {
yield* iterArr(arr[i]); // (*)递归
}
} else {
// 离开
yield arr;
}
}
// 使用 for-of 遍历:
var arr = ["a", ["b", "c"], ["d", "e"]];
for (var x of iterArr(arr)) {
console.log(x); // a b c d e
}
// 或者直接将迭代器展开:
var arr = ["a", ["b", ["c", ["d", "e"]]]];
var gen = iterArr(arr);
arr = [...gen]; // ["a", "b", "c", "d", "e"]
Generator 原理
js
// 模拟实现
function* foo() {
yield "result1";
yield "result2";
yield "result3";
}
const gen = foo();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
// 生成器函数根据 yield 语句将代码分割为 switch-case 块,后续通过切换_context.prev和_context.next来分别执行各个case
function gen$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
_context.next = 2;
return "result1";
case 2:
_context.next = 4;
return "result2";
case 4:
_context.next = 6;
return "result3";
case 6:
case "end":
return _context.stop();
}
}
}
var context = {
next: 0,
prev: 0,
done: false,
stop: function stop() {
this.done = true;
},
};
let gen = function () {
return {
next: function () {
value = context.done ? undefined : gen$(context);
done = context.done;
return {
value,
done,
};
},
};
};
// 测试使用
var g = gen();
g.next(); // {value: "result1", done: false}
g.next(); // {value: "result2", done: false}
g.next(); // {value: "result3", done: false}
g.next(); // {value: undefined, done: true}
async 是 Generator 函数的语法糖,能解释一下吗
async + await => co + generator 语法糖
co
js
const fetchData = (data) => {
return new Promise((resolve, reject) => {
setTimeout(() =>{
resolve(data)
})
})
}
function* foo() {
let data1 = yield fetchData(1)
data1++;
let data2 = yield fetchData(data1)
data2++;
const data3 = yield fetchData(data2)
return data3;
}
function co(it) {
return new Promise(function (resolve, reject) {
function step(d) {
let { value, done } = it.next(d);
if (!done) {
value.then(function (data) { // 2,txt
console.log(data);
step(data)
}, reject)
} else {
resolve(value);
}
}
step();
});
}
co(foo()).then(function (data) {
console.log(data)
})